package role

import (
	"encoding/json"
	"fmt"
	"sanguo/cluster"
	"sanguo/node/common/GlobalConstData"
	com_attr "sanguo/node/common/attr"
	"sanguo/node/common/module"
	"sanguo/node/node_game"
	"sanguo/node/node_game/module/role/InstanceZone"
	"sanguo/node/node_game/module/role/achievement"
	role_attr "sanguo/node/node_game/module/role/att"
	"sanguo/node/node_game/module/role/bag"
	"sanguo/node/node_game/module/role/battleGround"
	"sanguo/node/node_game/module/role/battle_attr"
	"sanguo/node/node_game/module/role/bossZone"
	"sanguo/node/node_game/module/role/drawCard"
	"sanguo/node/node_game/module/role/mission"
	"sanguo/node/node_game/module/role/skill"
	"sanguo/node/node_game/module/role/team"
	"sanguo/node/node_game/user"
	cs_message "sanguo/protocol/cs/message"

	"time"

	"github.com/golang/protobuf/proto"
)

type saveAble interface {
	IsDirty() bool
	SetDirtyFlag()
	ClearDirtyFlag()
	PackJson(map[string]interface{})
}

type RoleData struct {
	ID         uint64 //角色ID
	Lev        int32  //角色等级
	Name       string //角色名
	Used       int32  //当前是否正在使用
	Portrait   int32  //头像
	Face       int32
	Hair       int32
	HairColor  int32
	EyeColor   int32
	Cloth      int32
	ClothColor int32
	AreaID     int32 //角色区服ID
	Outline    int32 //外形
	Weapon1    int32 //主武器
	Weapon2    int32 //副武器

	//所处地图及坐标
	MapID int32
	X     int32
	Y     int32
	Z     int32
	Angle int32

	//上次下线时间，没有被选用过的角色不会改变
	LastLogout int64
}

type Role struct {
	data                   RoleData
	dirty                  bool
	module                 map[string]saveAble
	battleAttr             *battle_attr.RoleBattleAttr //战斗属性
	attr                   *role_attr.RoleAttr         //通用属性
	mission                *mission.RoleMission        //任务
	weapon                 *bag.RoleWeapon             // 武器
	soul                   *bag.RoleSoul               //武魂
	item                   *bag.RoleItem               // 道具
	weaponShard            *bag.RoleWeaponShard        //武器碎片
	skill                  *skill.RoleSkill            //角色技能
	starMap                *achievement.RoleStarMap    //星图成就
	battleGround           *battleGround.BattleGround  //英魂战场
	instanceZone           *InstanceZone.InstanceZone  //副本奖励
	drawCard               *drawCard.RoleDrawCard      //抽卡
	bossZone               *bossZone.RoleBossZone      //boos副本
	NodeMap                *cluster.PeerID
	NodeChat               *cluster.PeerID
	NodeBattle             *cluster.PeerID
	Team                   *team.Team
	user                   *user.User
	nextRecoverActionPoint int64 //上次恢复体力的时间
	nextRefreshTime        int64 //下一刷新角色所有属性的时间
	selectRoleOk           bool
}

func (this *Role) GetData() RoleData {
	return this.data
}

func (this *Role) GetUserID() string {
	return this.user.GetUserID()
}

func (this *Role) IsUsed() bool {
	return this.data.Used == 1
}

func (this *Role) ToJsonStr() ([]byte, error) {
	return json.Marshal(&this.data)
}

func (this *Role) GetID() uint64 {
	return this.data.ID
}

func (this *Role) GetOutline() int32 {
	return this.data.Outline
}

func (this *Role) GetLev() int32 {
	return this.data.Lev
}

func (this *Role) SetLev(lev int32) {
	if this.data.Lev != lev {
		this.data.Lev = lev
		this.dirty = true
	}
}

func (this *Role) GetName() string {
	return this.data.Name
}

func (this *Role) SetName(name string) {
	if this.data.Name != name {
		this.data.Name = name
		this.dirty = true
	}
}

func (this *Role) GetPortrait() int32 {
	return this.data.Portrait
}

func (this *Role) SetPortrait(p int32) {
	this.data.Portrait = p
}

func (this *Role) GetPos() (int32, int32, int32) {
	return this.data.X, this.data.Y, this.data.Z
}

func (this *Role) SetPos(x, y, z int32) {
	if this.data.X != x ||
		this.data.Y != y ||
		this.data.Z != z {
		this.data.X = x
		this.data.Y = y
		this.data.Z = z
		this.dirty = true
	}
}

func (this *Role) GetAngle() int32 {
	return this.data.Angle
}

func (this *Role) SetAngle(angle int32) {
	if this.data.Angle != angle {
		this.data.Angle = angle
		this.dirty = true
	}
}

func (this *Role) GetMapID() int32 {
	return this.data.MapID
}

func (this *Role) SetMapID(mapID int32) {
	if this.data.MapID != mapID {
		this.data.MapID = mapID
		this.dirty = true
	}
}

func (this *Role) GetWeapon1() int32 {
	return this.data.Weapon1
}

func (this *Role) GetWeapon2() int32 {
	return this.data.Weapon2
}

func (this *Role) SetWeapon1(weapon int32) {
	if this.data.Weapon1 != weapon {
		this.data.Weapon1 = weapon
		this.dirty = true
	}
}

func (this *Role) SetWeapon2(weapon int32) {
	if this.data.Weapon2 != weapon {
		this.data.Weapon2 = weapon
		this.dirty = true
	}
}

func (this *Role) GetClothColor() int32 {
	return this.data.ClothColor
}

func (this *Role) SetClothColor(clothColor int32) {
	if this.data.ClothColor != clothColor {
		this.data.ClothColor = clothColor
		this.dirty = true
	}
}

func (this *Role) GetCloth() int32 {
	return this.data.Cloth
}

func (this *Role) SetCloth(cloth int32) {
	if this.data.Cloth != cloth {
		this.data.Cloth = cloth
		this.dirty = true
	}
}

func (this *Role) GetFace() int32 {
	return this.data.Face
}

func (this *Role) SetFace(face int32) {
	if this.data.Face != face {
		this.data.Face = face
		this.dirty = true
	}
}

func (this *Role) GetHair() int32 {
	return this.data.Hair
}

func (this *Role) SetHair(hair int32) {
	if this.data.Hair != hair {
		this.data.Hair = hair
		this.dirty = true
	}
}

func (this *Role) GetEyeColor() int32 {
	return this.data.EyeColor
}

func (this *Role) SetEyeColor(eyeColor int32) {
	if this.data.EyeColor != eyeColor {
		this.data.EyeColor = eyeColor
		this.dirty = true
	}
}

func (this *Role) GetHairColor() int32 {
	return this.data.HairColor
}

func (this *Role) SetHairColor(hairColor int32) {
	if this.data.HairColor != hairColor {
		this.data.HairColor = hairColor
		this.dirty = true
	}
}

func (this *Role) SetLastLogout(t int64) {
	if this.data.LastLogout != t {
		this.data.LastLogout = t
		this.dirty = true
	}
}

func (this *Role) SetSelectRoleOk(b bool) {
	this.selectRoleOk = b
}

func (this *Role) GetSelectRoleOk() bool {
	return this.selectRoleOk
}

func (this *Role) Tick(now time.Time) {
	if now.Unix() > this.nextRecoverActionPoint {
		this.nextRecoverActionPoint = now.Unix() + int64(GlobalConstData.RecoverActionPoint)
		this.AddActionPoint(1)
	}

	//日刷新
	if now.Unix() > this.nextRefreshTime {
		this.nextRefreshTime += 86400 //24 * 60 * 60
		this.RefreshRole()
	}

	//队伍心跳
	if this.Team != nil && this.user.CcheckStatus(status_playing) {
		this.Team.Heartbeat(this.GetID(), now)
	}
}

//每天定时刷新玩家所有属性
func (this *Role) RefreshRole() {
	node_game.Debugln(this.GetUserID(), this.GetID(), " -------------------------- Refresh ")
	//任务

	//英魂战场免费次数
	this.GetRoleAttr().SetAttr(com_attr.YHBattleGroundEnterTimes, int64(GlobalConstData.YHBattleGroundEnterTimes))

	//道具使用次数
	this.GetRoleItem().RefreshItemUseTimes()
	this.OnItemDirty()

}

type RoleModule struct {
	user        *user.User
	roleList    map[uint64]*Role
	currentRole *Role
}

func (this *RoleModule) Tick(now time.Time) {
	if this.CurrentRole() != nil {
		if this.currentRole.IsRoleModleData() {
			this.currentRole.Tick(now)
		}
	}
}

func (this *RoleModule) Init(args ...interface{}) bool {

	if len(args) != 1 {
		return false
	}

	roles := args[0].(map[string]string)
	for _, v := range roles {
		var role RoleData
		err := json.Unmarshal(([]byte)(v), &role)

		if err != nil {
			return false
		}
		if !this.AddRole(&role) {
			return false
		}
	}
	this.ReportMaxLev()
	return true
}

func (this *RoleModule) Name() string {
	return "role"
}

func (this *RoleModule) GetRoleCount() int32 {
	var roleCount int32 = 0
	for _, v := range this.roleList {
		if v.data.AreaID == this.user.GetEnterAreaID() {
			roleCount++
		}
	}
	return roleCount
}

//增加角色
func (this *RoleModule) AddRole(role *RoleData) bool {
	if nil == role {
		return false
	}
	_, ok := this.roleList[role.ID]
	if ok {
		return false
	} else {
		r := &Role{data: *role, user: this.user, module: map[string]saveAble{}}
		this.roleList[role.ID] = r
		//		if role.Used == 1 && role.AreaID == this.user.GetEnterAreaID() {
		//			this.currentRole = r
		//		}
		return true
	}
	return true
}

func (this *RoleModule) OnSelectRole(r *Role) {

	var refreshTime time.Time
	//所有系统刷新时间
	if r.nextRefreshTime == 0 {
		refreshTimeStr := GlobalConstData.RefreshTime
		refreshTime, _ = time.ParseInLocation("2006-01-02 15:04:05", fmt.Sprintf("%s %s", time.Now().Format("2006-01-02"), refreshTimeStr), time.Local)
		r.nextRefreshTime = refreshTime.Unix() //UTC +08:00
		if time.Now().Unix() > r.nextRefreshTime {
			r.nextRefreshTime += 86400 //24 * 60 * 60
		}
	}

	if 0 != r.data.LastLogout {
		elapse := time.Now().Unix() - r.data.LastLogout
		if elapse > 0 {
			//恢复体力
			point := elapse / int64(GlobalConstData.RecoverActionPoint)
			r.AddActionPoint(point)
			r.nextRecoverActionPoint = time.Now().Unix() + GlobalConstData.RecoverActionPoint
		}

		if time.Now().Unix() >= refreshTime.Unix() && refreshTime.Unix() >= r.data.LastLogout {
			r.RefreshRole()
		}

		r.SetLastLogout(0)
	}

}

//选择角色
func (this *RoleModule) SelectRole(id uint64) bool {
	r := this.roleList[id]
	if nil != r {
		this.OnLogout()
		this.currentRole = r
		this.OnSelectRole(r)
		return true
	} else {
		return false
	}
}

func (this *RoleModule) CurrentRole() *Role {
	return this.currentRole
}

func (this *RoleModule) GetRole(id uint64) *Role {
	return this.roleList[id]
}

//更改角色used 返回需要更改的角色id
func (this *RoleModule) ChangeRoleUsed(id uint64) []uint64 {
	otherIDs := []uint64{}
	for _, v := range this.roleList {
		if v.data.AreaID == this.user.GetEnterAreaID() {
			if v.data.ID == id && v.data.Used == 0 {
				v.data.Used = 1
				v.dirty = true
			} else if v.data.ID != id && v.data.Used == 1 {
				v.data.Used = 0
				v.dirty = true
				otherIDs = append(otherIDs, v.data.ID)
			}
		}
	}
	return otherIDs
}

//删除角色
func (this *RoleModule) DelRole(id uint64) bool {
	_, ok := this.roleList[id]
	if ok {
		delete(this.roleList, id)
		return true
	} else {
		return false
	}
	return false
}

//上报当前服角色最大等级
func (this *RoleModule) ReportMaxLev() {
	var maxLev int32 = 0
	for _, v := range this.roleList {
		if maxLev < v.data.Lev && v.data.AreaID == this.user.GetEnterAreaID() {
			maxLev = v.data.Lev
		}
	}
	if maxLev != 0 {
		//node_game.Infoln(this.user.GetUserID(), ": ReportUserLogout maxLev", maxLev)
		node_game.ReportUserLog(this.user.GetUserID(), maxLev, this.user.GetEnterAreaID())
	}
}

func (this *RoleModule) PackRoleList() *cs_message.RoleListToC {
	msg := &cs_message.RoleListToC{}
	for _, v := range this.roleList {
		if v.data.AreaID == this.user.GetEnterAreaID() {
			r := &cs_message.Role{
				ID:         proto.Uint64(v.data.ID),
				Lev:        proto.Int32(v.data.Lev),
				Name:       proto.String(v.data.Name),
				Used:       proto.Int32(v.data.Used),
				Portrait:   proto.Int32(v.data.Portrait),
				Face:       proto.Int32(v.data.Face),
				Hair:       proto.Int32(v.data.Hair),
				HairColor:  proto.Int32(v.data.HairColor),
				EyeColor:   proto.Int32(v.data.EyeColor),
				Cloth:      proto.Int32(v.data.Cloth),
				ClothColor: proto.Int32(v.data.ClothColor),
				Outline:    proto.Int32(v.data.Outline),
				Weapon1:    proto.Int32(v.data.Weapon1),
				Weapon2:    proto.Int32(v.data.Weapon2),
				AreaID:     proto.Int32(v.data.AreaID),
			}
			msg.RoleList = append(msg.RoleList, r)
		}
	}
	return msg
}

func (this *RoleModule) Save(callback func(error)) {

	if len(this.roleList) == 0 {
		if callback != nil {
			callback(nil)
		}
	} else {
		flags := map[uint64]bool{}
		for k, _ := range this.roleList {
			flags[k] = true
		}
		for k, v := range this.roleList {
			roleID := k
			v.Save(func(err error) {
				if nil == err {
					delete(flags, roleID)
					if 0 == len(flags) && nil != callback {
						callback(err)
					}
				} else if nil != callback {
					cb := callback
					callback = nil
					cb(err)
				}
			})
		}
	}
}

func init() {
	user.RegisterModule("role", func(u *user.User) module.Module {
		return &RoleModule{
			user:     u,
			roleList: map[uint64]*Role{},
		}
	})
}
